﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Tenta_v1_5
{
    class HT<TKey, TValue> : IEnumerable<TValue> where TValue : class
    {
        private Node<TKey, TValue> head;

        private Node<TKey, TValue>[] table;

        public HT(int size = 97)
        {
            table = new Node<TKey, TValue>[size];
            for (int i = 0; i < size; i++ )
                table[i] = null;
            head = null;
        }

        public void Add(TKey key, TValue value)
        {
            int index = Math.Abs(key.GetHashCode() % table.Count());
            if (table[index] == null)
            {
                if (index == 0)
                    head = table[index] = new Node<TKey, TValue>(key, value, head);
                else
                {
                    Node<TKey, TValue> n = FindPrevious(index);
                    if (n == null)
                        head = table[index] = new Node<TKey, TValue>(key, value, null);
                    else
                        n.Next = table[index] = new Node<TKey, TValue>(key, value, n.Next); 
                }
            }
            else
            {
                table[index].Next = new Node<TKey, TValue>(key, value, table[index].Next);
            }
        }

        private Node<TKey, TValue> FindPrevious(int index)
        {
            int i = 1;
            while (table[index - i] == null)
            { 
                i++;
                if (index - i < 0)
                    return null;
            }
            Node<TKey, TValue> n = table[index - i];
            while (n.Next != null)
            {
                if (Math.Abs(n.Next.Key.GetHashCode() % table.Count()) == index - i)
                    n = n.Next;
                else
                    break;
            }
            return n;
        }
        
        public Node<TKey, TValue> Search(TKey key)
        {
            int index = Math.Abs(key.GetHashCode() % table.Count());
            Node<TKey, TValue> n = table[index];
            while(n != null)
            {
                if (n.Key.Equals(key))
                    return n;
                else
                    n = n.Next;
            }
            return n;
        }

        public void Print()
        {
            for (int i = 0; i < table.Count(); i++)
            {
                Node<TKey, TValue> n = table[i];
                if (n != null)
                {
                    Console.Write(i + " :");
                    while (Math.Abs(n.Key.GetHashCode() % table.Count()) ==  i)
                    {
                        Console.Write(string.Format("- {0,8:X} : {1,4} : {2,4} ", n.Key.GetHashCode(), n.Key.ToString(), n.Value.ToString()));
                        if (n.Next == null)
                            break;
                        else
                            n = n.Next;
                    }
                    Console.WriteLine();
                }
            }
        }

        public IEnumerator<TValue> GetEnumerator()
        {
            Node<TKey, TValue> n = head;
            while (n != null)
            {
                yield return n.Value;
                n = n.Next;
            }
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
}